- Overview of the Gray Council PowerPlant adapter classes.
- Instructions for using the PowerPlant adapter classes.
Instructions for building the Gray Council PowerPlant sample/test application.
1. Open the .π file of choice (68K or PowerPC) with CodeWarrior.
2. Select the Run command to compile, link, and launch the application.
Overview of the Gray Council PowerPlant adapter classes.
AGAWindowPP (ID='GCwn')
Replacement subclass of LWindow. Gives the window the AGA modeless shaded gray background.
AGADialogBoxPP (ID='GCdb')
Replacement subclass of LDialogBox. Gives the window the AGA modal shaded gray background, and knows how to replace the standard LDialogBox default button outline mechanism with the Gray Council's push button outline attribute.
AGAPushButtonPP (ID='GCpb')
Replacement subclass of LStdButton. Implements the AGA pushbutton by instantiating a core AGAPushButton object.
Recommended dimensions: 20x64 or 20x80, or wider to fit longer title.
AGACheckBoxPP (ID='GCcb')
Replacement subclass of LStdCheckBox. Implements the AGA check box by instantiating a core AGACheckBox object. To use the "mixed-state" capability, call LStdCheckBox::SetValue(AGACheckBox::kCheckBoxMixed).
Minimum dimensions: 12xY.
AGARadioButtonPP (ID='GCrb')
Replacement subclass of LStdRadioButton. Implements the AGA radio button by instantiating a core AGARadioButton object. To use the "mixed-state" capability, call LStdRadioButton::SetValue(AGARadioButton::kRadioButtonMixed).
Minimum dimensions: 12xY.
AGAIconPushButtonPP (ID='GCip')
Replacement subclass of AGAPushButtonPP (LStdButton), acts like a regular springloaded pushbutton, but with icon button appearance. Implements the AGA icon button by instantiating a core AGAIconPushButton object. The mUserCon should contain the icon family resource ID.
Recommended dimensions: 22x22 for small icons, 40x40 for large icons.
AGAIconPushButtonPPX (ID='GXip')
Extended subclass of AGAIconPushButtonPP (LStdButton), for use with the supplied CPPb custom pane type. Reads the icon family resource ID from additional data in the pane stream instead of using the mUserCon.
Recommended dimensions: same as for AGAIconPushButtonPP.
AGAIconCheckBoxPP (ID='GCic')
Replacement subclass of AGACheckBoxPP (LStdCheckBox), acts like a regular self-toggling check box, but with icon button appearance. Implements the AGA icon check box by instantiating a core AGAIconCheckBox object. The mUserCon should contain the icon family resource ID.
Recommended dimensions: 22x22 for small icons, 40x40 for large icons.
AGAIconCheckBoxPPX (ID='GXic')
Extended subclass of AGAIconCheckBoxPP (LStdCheckBox), for use with the supplied CPPb custom pane type. Reads the off and on icon family resource IDs from additional data in the pane stream instead of using the mUserCon for both.
Recommended dimensions: same as for AGAIconCheckBoxPP.
AGAIconRadioButtonPP (ID='GCir')
Replacement subclass of AGARadioButtonPP (LStdRadioButton), acts like a regular radio button that can be grouped in an LRadioGroup for mutual exclusivity, but with icon button appearance. Implements the AGA icon radio button by instantiating a core AGAIconRadioButton object. The mUserCon should contain the icon family resource ID.
Recommended dimensions: 22x22 for small icons, 40x40 for large icons.
AGAIconRadioButtonPPX (ID='GXir')
Extended subclass of AGAIconRadioButtonPP (LStdRadioButton), for use with the supplied CPPb custom pane type. Reads the off and on icon family resource IDs from additional data in the pane stream instead of using the mUserCon for both.
Recommended dimensions: same as for AGAIconRadioButtonPP.
AGAGroupBoxPP (ID='GCgb')
Replacement subclass of LGroupBox. Implements AGA primary group box by instantiating a core AGAGroupBox set for "primary" look. If the mUserCon contains the pane ID of a sibling pane, that other pane's width will be used to determine the "title gap" that is left blank for the other pane to occupy; otherwise, the LGroupBox title is used.
Recommended dimensions: n/a; fit to contain subviews. If you use a sibling pane for the title gap, you'll need to locate it at the correct location to sit in the title gap. As an example, if you use a 16xY check box for the group box title, the check box pane should be located at left+14, top-9 relative to the group box. To conform precisely to the AGA guidelines, the title's baseline should match the group box top, and there should be 3 blank pixels on each side of the title.
AGAGroupBoxPPX (ID='GXgb')
Extended subclass of AGAGroupBoxPP (LGroupBox), for use with the supplied CPPb custom pane type. Reads the primary/secondary flag and gap pane ID from additional data in the pane stream instead of using the mUserCon for the ID and assuming primary.
Recommended dimensions: same as for AGAGroupBoxPP.
AGASecondaryGroupBoxPP (ID='GCgs')
Replacement subclass of AGAGroupBoxPP (LGroupBox). Implements AGA secondary group box by instantiating a core AGAGroupBox set for "secondary" look.
Recommended dimensions: same as for AGAGroupBoxPP.
AGAScrollBarPP (ID='GCsb')
Replacement subclass of LStdControl/scrollBarProc. Implements the AGA scroll bar by instantiating a core AGAScrollBar. By default, live scrolling is on and proportional indicator is off. You can change these defaults globally via SetGrayCouncilDefault or per object via SetAttributes. For use with an LScroller, you don't create the scroll bar objects; use AGAScrollerPP instead of LScroller and it will create the scroll bars.
Recommended dimensions: Xx16 or 16xY.
AGAScrollerPP (ID='GCsc')
Replacement subclass of LScroller. Implements the AGA scroll bars by replacing each of the normal scroll bars created by LScroller with a core AGAScrollBar.
Recommended dimensions: whatever fits.
AGASliderPP (ID='GCsl')
A subclass of LControl. Implements AGA slider by instantiating a core AGASlider. If the mUserCon contains a valid STR# resource ID, the slider will be labeled/pointy, and the slider labels are read from that resource. Otherwise, the slider will be unlabeled/rectangular. The slider's range and initial value are set from the LControl settings.
Minimum dimensions: Xx17 or 17xY.
AGASliderPPX (ID='GXsl')
Extended subclass of AGASliderPP (LControl), for use with the supplied CPPb custom pane type. Reads the labels STR# resource ID from additional data in the pane stream instead of using the mUserCon, plus the labels text traits ID and slider justification setting.
Recommended dimensions: same as for AGASliderPP.
AGALittleArrowsPP (ID='GCla')
A subclass of LControl. Implements AGA little arrows by instantiating a core AGALittleArrows. If the mUserCon contains the pane ID of an LEditField pane in the same window, the little arrows will automatically increment/decrement the number in the edit field, limited by the min/max range of the little arrows LControl.
Minimum dimensions: 23x13.
AGALittleArrowsPPX (ID='GXla')
Extended subclass of AGALittleArrowsPP (LControl), for use with the supplied CPPb custom pane type. Reads the attatched numeric field pane ID from additional data in the pane stream instead of using the mUserCon.
Recommended dimensions: same as for AGALittleArrowsPP.
AGAPopupMenuPP (ID='GCpo')
Replacement subclass of LStdPopupMenu. Implements the AGA popup menu by instantiating a core AGAPopupMenu.
Recommended dimensions: 20xY. Supports variable or fixed width option; fixed width means that the view is always drawn to fill the width of the view, while variable means it shrinks to fit the actual width of the menu item data.
AGADisclosureTrianglePP (ID='GCdt')
A subclass of LControl. Implements AGA disclosure triangle by instantiating a core AGADisclosureTriangle.
Minimum dimensions: 10x10.
AGAProgressIndicatorPP (ID='GCpr')
A subclass of LControl. Implements AGA determinate and indeterminate progress indicators by instantiating a core AGAProgress indicator. The min/max/value of the LControl are used for the progress indicator. If you set min=max, you get an indeterminate indicator. Call mAGAObject->Animate to rotate an indeterminate indicator once.
Required dimensions: Xx14.
AGAWhiteBackgroundAttachmentPP (ID='GCwa')
A subclass of LAttachment. To get a white pane background against a gray window background, attach one of these to the pane. This attachment will be common for editable text views and list views, usually used with a AGABorderFrameAttachmentPP. AGAEditFieldPP, AGATextEditPP, and AGAListBoxPP automatically attach one of these for you.
AGABorderFrameAttachmentPP (ID='GCba')
A subclass of LAttachment. To get a "3D" sunken subview frame, attach one of these to the pane. This attachment will be common for editable text views and list views, usually used with a AGAWhiteBackgroundAttachmentPP. AGAEditFieldPP, AGATextEditPP, and AGAListBoxPP automatically attach one of these for you.
AGAEditFieldPP (ID='GCed')
Replacement subclass of LEditField. Implements the AGA editable text field by automatically attaching an AGAWhiteBackgroundAttachmentPP and an AGABorderFrameAttachmentPP to the pane. It also knows how to correctly draw the disabled text frame in gray.
Recommended dimensions: depends on text size. 20xY is suitable for Chicago 12.
AGATextEditPP (ID='GCte')
Replacement subclass of LTextEdit. Implements the AGA editable text field by automatically attaching an AGAWhiteBackgroundAttachmentPP and an AGABorderFrameAttachmentPP to the pane.
Recommended dimensions: depends on text size and content.
AGASeparatorPP (ID='GCse')
A subclass of LPane. Implements AGA separator by instantiating a core AGASeparator. The larger dimension (h/v) is the direction that the separator is drawn.
Minimum dimensions: Xx2 or 2xY.
AGACaptionPP (ID='GCca')
Replacement subclass of LCaption. Implements static text that draws disabled in "real" gray (not qd.gray erase patBic), and erases to gray on a non-white background, by instantiating a core AGAStaticText. You can just use LCaption if you do not change the text while the window is visible, but if you update the text while the window is open, use AGACaptionPP to avoid a white hole in the window.
Recommended dimensions: n/a; depends on font size.
AGAListBoxPP (ID='GClb')
Replacement subclass of LListBox. Implements the AGA list box by automatically attaching an AGAWhiteBackgroundAttachmentPP and an AGABorderFrameAttachmentPP to the pane. It also replaces the standard LFocusBox with an AGAFocusBoxPP that draws an AGA-style focus frame.
Recommended dimensions: n/a; fit to contents.
AGAFocusBoxPP (ID='GCfb')
Replacement subclass of LFocusBox. Implements AGA keyboard focus frame by drawing the frame with the correct color and shape. AGAListBoxPP automatically uses an AGAFocusBoxPP to replace its standard LFocusBox that is created by LListBox.
Recommended dimensions: n/a; fit to box pane.
Instructions for using the Gray Council PowerPlant adapter classes.
1. Adding the Gray Council files to your project.
Your project needs to add two Gray Council files:
- GrayCouncil.cpp (the core classes)
- GrayCouncilPP.cpp (the PowerPlant adapter classes)
Adding these files will create the needed access paths. The PowerPlant stationery should have the remaining access paths set up correctly so you don't have to change them.
The Gray Council .cpp and .h files don't rely on any particular folder hierarchy, so you can organize them however you want. (However, the provided sample app has certain relative file path assumptions, as discussed earlier.)
If you used the PowerPlant project stationery supplied with CodeWarrior 9 to create your project file, the "Panes" section is probably missing "LGroupBox.cp", so you should add it to the project. LGroupBox.cp is located in the PowerPlant "Pane Classes" folder.
Finally, you need to add the PLStringFuncs glue, which is used by the core Gray Council code.
The 68K version is ":MacOS Support:Libraries:MacOS 68K:MacOS Files:PLStringFuncs.glue.lib"
The PPC version is ":MacOS Support:Libraries:MacOS PPC:PLStringFuncs Glue:PLStringFuncsPPC.lib"
2. Enabling RTTI.
There are a couple of places in the PowerPlant adapter classes where run-time type information is used. You have a choice here.
If you don't have some reason not to, you can turn on the "Enable RTTI" checkbox in the project's C/C++ Language preferences panel. This will enable the proper RTTI testing in the code.
If for some reason you can't enable RTTI, you'll get several "RTTI not enabled" warnings from the compiler. To defeat these, simply #define NO_RTTI either in a prefix file or in GrayCouncilPP.h. This will avoid the code that uses RTTI, but you'll have mentally promise that you're using the correct types because there will be no type-checking in these two cases:
- When you use AGADialogBoxPP for a dialog, your default button (typically the OK button), which is identified by the dialog pane's mDefaultButtonID value, must be an AGAPushButtonPP object. If it's just a standard LStdButton, you will crash. You can override AGADialogBoxPP::SetDefaultButton if you need to work around this issue.
- When you use AGALittleArrowsPP, and you specify a linked edit field pane to be incremented/decremented by the little arrows, the linked pane must indeed be an LEditField or subclass or you will crash. You can override AGALittleArrowsPP::CreateAGAObject() if you need to work around this issue.
3. Initializing.
You must call InitGrayCouncilPP() after PowerPlant has initialized the toolbox but before you instantiate any Gray Council objects. You should ThrowIfOSErr_() on the result. This function call registers the PowerPlant adapter classes and then calls InitGrayCouncil.
4. Specifying the pane ID.
(Note: feel free to open the file MyApplication.rsrc (in the Gray Council sample PowerPlant app folder) with Constructor to see the details of the resources used for the sample app.)
For PPob view panes, you just need to set the class ID of the pane in the resource. This applies to window and dialog root view panes (for AGAWindowPP and AGADialogBoxPP), to panes inside a window, and to attachments. For most of the adapter classes, this is all you need to do; in some of the fancier classes, you will also want to set attributes at runtime. Some classes also support use of the mUserCon field to specify attributes; there are also extended versions of these classes that require use of the CPPb custom pane types (see below for details on this).
So, you simply open the pane's information window, go to the "Class ID" field and type in the new four-letter class ID value. These class IDs are noted in the detailed class descriptions above.
For example, to use an AGAPushButtonPP in a window:
- Drag an LStdButton object from the Constructor display classes window into the layout grid.
- Open the button's information window.
- Set the Class ID to GCpb.
5a. Setting the mUserCon.
The following summarizes how the "user constant" or mUserCon field of a pane in a resource specifies additional information for certain classes (zero means to ignore it). This information is also listed in the class overviews above.
AGAIconPushButtonPP::mUserCon specifies the resource ID of an icon family for the icon button.
AGAIconCheckBoxPP::mUserCon specifies the resource ID of an icon family for the icon button.
AGAIconRadioButtonPP::mUserCon specifies the resource ID of an icon family for the icon button.
AGASliderPP::mUserCon specifies the STR# resource ID of the slider labels.
AGALittleArrowsPP::mUserCon specifies the ID of an LEditField pane in the same window to be automatically linked to the arrows.
AGAGroupBoxPP::mUserCon specifies the ID of a sibling pane whose width will be used to determine the "title gap" of the group box.
5b. Using the CPPb custom pane type subclasses.
Each of the classes listed above in 5a has an extended subclass (class names ending in "PPX" instead of "PP") that you can use if using the mUserCon is not sufficient, or if you're using the mUserCon for something else. The classes that do not use the mUserCon don't need any additional information, and therefore do not need an extended class or custom pane type.
To use the extended subclasses, open the file "GCCustomPaneTypes.rsrc" with Constructor. This file is located in the Gray Council :source:PowerPlant: folder. You will see the custom pane types for the extended subclasses. There are three ways to make the custom pane types available to Constructor:
- Place GCCustomPaneTypes.rsrc in the Constructor application folder; Constructor will see it when launched.
- or, Paste the custom pane types into your app's pane resource file that will be edited with Constructor.
- or, Always open GCCustomPaneTypes.rsrc while editing your app's pane resource file with Constructor.
Be aware that if you use a custom pane type (any custom pane type, not just the Gray Council ones), you will need to have it available in one of these three ways in order to edit the pane with Constructor. If you try to open a view that contains a pane whose custom pane type definition is not available, Constructor will make you delete the pane before you can edit the view.
If you look at Constructor's display classes window, with the Gray Council custom pane types available, the hierarchy will show the custom pane types nested under their standard PowerPlant superclasses. To use a custom pane, just drag it into the view as you would a standard pane type. When you open the pane's information window (command-I or return), you will see the extra information field(s) at the bottom of the window, and the class ID will already be set to the extended class ID. Set the extra information fields how you want them, and when the pane is instantiated it will read the information from the PPob stream.
6. Changing attributes at runtime.
Once you have a Gray Council pane instantiated, you will want to do something with it! For the PowerPlant replacement subclasses, you can probably just plug them in; all standard functions like LControl::SetValue and LCaption::SetDescriptor will continue to work for the replacement subclasses. The only thing you need to avoid (and you should already be avoiding this) is for LStdControl subclasses, don't set or get the control manager value directly. You can continue to use the pane Set/GetValue functions, and you'll still be OK.
For some classes, there is no PowerPlant equivalent, so you'll need to call the view's mAGAObject-> functions directly. (This is why the mAGAObject data member is made public: so you can just call though without going through an accessor.) There is really only one thing to be careful of: focusing. Because the core AGA classes are designed to be ultra lightweight, they do not store a GrafPtr. They assume that the port is set up by the caller. So you must make sure that the view is focused before you explicitly call an AGAObject function that will cause drawing. The PowerPlant adapter classes already do this by calling this->FocusDraw() where necessary.